<!--
 * @Description  : 
 * @Version      : 1.0
 * @Author       : seraph
 * @Date         : 2025-02-18 17:00:08
 * @LastEditors  : seraph
 * @LastEditTime : 2025-02-19 13:15:43
-->
<template>
    <h3>v-for​</h3>
    <p>我们可以使用 v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法，其中 items 是源数据的数组，而 item 是迭代项的别名：</p>
    <pre><code class="javascript" v-html="highlighted(rawCode1, 'javascript')"></code></pre>
    <pre><code class="html" v-html="highlighted(rawCode2, 'html')"></code></pre>
    <p>
        <span>运行结果：</span>
        <li v-for="item in items">{{ item.message }}</li>
    </p>
    <br>

    <p>在 v-for 块中可以完整地访问父作用域内的属性和变量。v-for 也支持使用可选的第二个参数表示当前项的位置索引。</p>
    <pre><code class="javascript" v-html="highlighted(rawCode3, 'javascript')"></code></pre>
    <pre><code class="html" v-html="highlighted(rawCode4, 'html')"></code></pre>
    <p>
        <span>运行结果：</span>
        <li v-for="(item, index) in items">
            {{ parentMessage }} - {{ index }} - {{ item.message }}
        </li>
    </p>
    <br>

    <p>v-for 变量的作用域和下面的 JavaScript 代码很类似：</p>
    <pre><code class="javascript" v-html="highlighted(rawCode5, 'javascript')"></code></pre>
    <br>

    <p>注意 v-for 是如何对应 forEach 回调的函数签名的。实际上，你也可以在定义 v-for 的变量别名时使用解构，和解构函数参数类似：</p>
    <pre><code class="html" v-html="highlighted(rawCode6, 'html')"></code></pre>
    <br>

    <p>对于多层嵌套的 v-for，作用域的工作方式和函数的作用域很类似。每个 v-for 作用域都可以访问到父级作用域：</p>
    <pre><code class="html" v-html="highlighted(rawCode7, 'html')"></code></pre>
    <br>

    <p>你也可以使用 of 作为分隔符来替代 in，这更接近 JavaScript 的迭代器语法：</p>
    <pre><code class="html" v-html="highlighted(rawCode8, 'html')"></code></pre>
</template>

<script lang="ts" setup>
import { ref, nextTick, watch, Ref, onMounted } from 'vue'
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';
import javascript from 'highlight.js/lib/languages/javascript';
import html from 'highlight.js/lib/languages/xml';

hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('html', html);

const highlighted = (code: string, type: string) => {
    return hljs.highlight(code, { language: type }).value.replace(/&amp;lt;/g, '&lt;').replace(/&amp;gt;/g, '&gt;')
}

const getRenderingHTML = (items: { element: Ref<HTMLElement | null>; html: Ref<string> }[]) => {
    items.forEach((item) => {
        nextTick(() => {
            if (item.element.value) {
                item.html.value = item.element.value.outerHTML
            }
        })
    })
}

const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
const rawCode1 = `const items = ref([{ message: 'Foo' }, { message: 'Bar' }])`

const rawCode2 = `<li v-for="item in items">
  {{ item.message }}
</li>`

const parentMessage = ref('Parent')
const rawCode3 = `const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])`

const rawCode4 = `<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>`

const rawCode5 = `const parentMessage = 'Parent'
const items = [
  /* ... */
]

items.forEach((item, index) => {
  // 可以访问外层的 parentMessage
  // 而 item 和 index 只在这个作用域可用
  console.log(parentMessage, item.message, index)
})`

const rawCode6 = `<li v-for="{ message } in items">
  {{ message }}
</li>

<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">
  {{ message }} {{ index }}
</li>`

const rawCode7 = `<li v-for="item in items">
  <span v-for="childItem in item.children">
    {{ item.message }} {{ childItem }}
  </span>
</li>`

const rawCode8 = `<div v-for="item of items"></div>`

</script>

<style scoped>
p {
    font-size: 16px;
    padding: 2px;
    margin: 5px 0;
}

/* 设置预格式化文本的样式 */
pre {
    /* 背景色 */
    background-color: #f1ffed;
    /* 边框 */
    border: 1px solid #ccc;
    /* 缩小内边距 */
    padding: 5px 5px 5px 10px;
    /* 允许滚动 */
    overflow: auto;
    /* 可选：设置上下外边距 */
    margin: 0px 0;
    /* 允许换行 */
    /* normal: 连续的空白字符会被合并为一个空格。文本会在允许的断点处自动换行。
     nowrap：连续的空白字符会被合并为一个空格。文本不会自动换行，即使在允许的断点处也不会换行。
     pre：保留所有的空白字符（包括空格、制表符和换行符）。文本只会在遇到换行符或者 <br> 标签时换行。
     pre-wrap：保留所有的空白字符。文本会在遇到换行符、<br> 标签，或者达到容器边界时换行。
     pre-line：合并连续的空白字符为一个空格，但保留换行符。文本会在遇到换行符、<br> 标签，或者达到容器边界时换行。
   */
    white-space: pre-wrap;
    /* 行高 */
    line-height: 120%;
    /* 定义缩进 */
    tab-size: 4;
}

h3,
h4,
h5,
h6 {
    margin: 25px 0 10px 0;
    line-height: 100%;
}

.bolder {
    font-weight: bolder;
}

.red {
    color: red;
}

button {
    margin: 5px 5px 5px 10px;
    line-height: 150%;
    width: auto;
    padding: 0 10px;
}

.active {
    color: red;
}

.static {
    font-weight: bolder;
}

.text-danger {
    font-style: italic;
}
</style>
